package com.basin.common.mp.base;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import com.basin.common.core.exception.BasinException;
import com.basin.common.core.response.ResponseResult;
import com.basin.common.core.util.NamingConvertUtil;
import com.basin.common.mp.annotation.RequireValFields;
import com.basin.common.mp.annotation.UniqueKeys;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @author: Sam ZHONG | sammy1997@aliyun.com
 */
public class BaseController<R extends CrudRepository<M, T>, T extends BaseEntity, M extends BaseMapper<T>> {
    private R repository;

    /**
     * 需要使用set方法注入服务bean，不然启动会报错 --- found n+ xxxImpl
     *
     * @param repository service
     */
    @Resource
    public void setRepository(R repository) {
        this.repository = repository;
    }

    public R getRepository() {
        return this.repository;
    }

    @PostMapping("/add")
    @Transactional(rollbackFor = {Exception.class})
    public ResponseResult<Boolean> add(@RequestBody T entity) throws Exception {
        // 数据唯一值校验
        uniqueKeysCheck(entity);
        // 非空字段校验
        requireValFieldsCheck(entity);
        beforeAdd(entity);
        boolean save = repository.save(entity);
        afterAdd(entity);
        return ResponseResult.success(save);
    }

    @PostMapping("/update")
    @Transactional(rollbackFor = {Exception.class})
    public ResponseResult<Boolean> update(@RequestBody T entity) {
        dbDataExistCheck(entity);
        beforeUpdate(entity);
        boolean update = repository.updateById(entity);
        afterUpdate(entity);
        return ResponseResult.success(update);
    }

    @PostMapping("/delete")
    @Transactional(rollbackFor = {Exception.class})
    public ResponseResult<Boolean> deleteById(@RequestBody T entity) {
        dbDataExistCheck(entity);
        beforeDelete(entity);
        boolean remove = repository.removeById(entity.getId());
        afterDelete(entity);
        return ResponseResult.success(remove);
    }

    @PostMapping("/query")
    public ResponseResult<IPage<T>> query(@RequestBody T entity) {
        beforeQuery(entity);
        Page<T> page = new Page<>(entity.getCurrent(), entity.getSize());
        // 查询条件
        LambdaQueryWrapper<T> wrapper = buildWrapper(entity);
        page = repository.page(page, Objects.requireNonNullElseGet(wrapper,
                () -> new QueryWrapper<>(entity).orderByDesc("create_time")));
        afterQuery(page, entity);
        return ResponseResult.success(page);
    }

    /**
     * 构建查询条件
     *
     * @param entity entity
     * @return 查询条件
     */
    public LambdaQueryWrapper<T> buildWrapper(T entity) {
        return null;
    }

    /**
     * 添加前
     *
     * @param entity 数据
     */
    public void beforeAdd(T entity) {
    }

    /**
     * 添加后
     *
     * @param entity 数据
     */
    public void afterAdd(T entity) {
    }

    /**
     * 修改前
     *
     * @param entity 数据
     */
    public void beforeUpdate(T entity) {
    }

    /**
     * 修改后
     *
     * @param entity 数据
     */
    public void afterUpdate(T entity) {
    }

    /**
     * 删除前
     *
     * @param entity 数据
     */
    public void beforeDelete(T entity) {
    }

    /**
     * 删除后
     *
     * @param entity 数据
     */
    public void afterDelete(T entity) {
    }

    /**
     * 查询前
     *
     * @param entity 数据
     */
    public void beforeQuery(T entity) {
    }

    /**
     * 查询后
     *
     * @param entity 数据
     */
    public void afterQuery(IPage<T> page, T entity) {
    }

    private void dbDataExistCheck(T entity) {
        T dbData = this.repository.getById(entity.getId());
        if (dbData == null) {
            throw new BasinException("数据不存在!");
        }
    }

    public void requireValFieldsCheck(T entity) {
        RequireValFields rf = entity.getClass().getDeclaredAnnotation(RequireValFields.class);
        if (rf != null) {
            String[] fields = rf.fields();
            if (fields != null) {
                for (String field : fields) {
                    try {
                        String name = NamingConvertUtil.toCamelCase(field);
                        Field df = entity.getClass().getDeclaredField(name);
                        df.setAccessible(true);
                        Object val = df.get(entity);
                        if (val == null || "".equals(val)) {
                            throw new BasinException("字段[" + name + "]不能为空！");
                        }
                    } catch (NoSuchFieldException | IllegalAccessException | BasinException e) {
                        throw new BasinException(e);
                    }

                }
            }
        }
    }

    public void uniqueKeysCheck(T entity) {
        UniqueKeys ks = entity.getClass().getDeclaredAnnotation(UniqueKeys.class);
        if (ks != null) {
            String[] fields = ks.fields();
            int type = ks.type();
            if (fields != null && fields.length > 0) {
                QueryWrapper<T> tQueryWrapper = new QueryWrapper<>();
                boolean check = false;
                for (String field : fields) {
                    try {
                        Field curField = entity.getClass().getDeclaredField(NamingConvertUtil.toCamelCase(field));
                        curField.setAccessible(true);
                        Object val = curField.get(entity);
                        if (val != null && !"".equals(val)) {
                            check = true;
                            if (type == 0) {
                                tQueryWrapper.or();
                            }
                            tQueryWrapper.eq(field, val);
                        }
                    } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
                        throw new BasinException("唯一校验异常：" + e.getMessage());
                    }
                }
                if (check) {
                    long count = this.repository.count(tQueryWrapper);
                    if (count > 0) {
                        throw new BasinException("数据已存在库中，不需要重复添加！");
                    }
                }
            }
        }
    }

}
